/***************************************************************************
 创建者: 华磊
 开始时间: 2020.8.14
 copyright: (C) 华友高科
 修改说明: (每次有修改就添加一条，带有 修改人，修改时间，修改描述)
 example (1) hualei 2020.5.8 类的具体实现代码编写

 ***************************************************************************
 *  @file x.h
 *  功能:
 *
 *                                                                         *
 ***************************************************************************/
#ifndef RINGQUEUE_H
#define RINGQUEUE_H


//复制代码
//type __sync_fetch_and_add (type *ptr, type value, ...)
//type __sync_fetch_and_sub (type *ptr, type value, ...)
//type __sync_fetch_and_or (type *ptr, type value, ...)
//type __sync_fetch_and_and (type *ptr, type value, ...)
//type __sync_fetch_and_xor (type *ptr, type value, ...)
//type __sync_fetch_and_nand (type *ptr, type value, ...)


//type __sync_add_and_fetch (type *ptr, type value, ...)
//type __sync_sub_and_fetch (type *ptr, type value, ...)
//type __sync_or_and_fetch (type *ptr, type value, ...)
//type __sync_and_and_fetch (type *ptr, type value, ...)
//type __sync_xor_and_fetch (type *ptr, type value, ...)
//type __sync_nand_and_fetch (type *ptr, type value, ...)
//复制代码
//这两组函数的区别在于第一组返回更新前的值，第二组返回更新后的值。
//有了这些函数, 就可以很方便的进行原子操作了, 以 count++ 为例,
//count 初始值为0, 可以这么写
//__sync_fetch_and_add(&count, 1);//返回0, count现在等于1, 类似 count ++
//count 初始值为0, 或者这么写
//__sync_add_and_fetch(&count, 1);//返回1, count现在等于1, 类似 ++ count

//bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...)
//type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...)
//这两个函数提供原子的比较和交换，如果*ptr == oldval,就将newval写入*ptr,
//第一个函数在相等并写入的情况下返回true.第二个函数在返回 *ptr 值。

//These builtins perform an atomic compare and swap. That is,
//if the current value of *ptr is oldval, then write newval into *ptr.

//  The “bool” version returns true if the comparison is successful and newval was written.
//  The “val” version returns the contents of *ptr before the operation.
//对于这种函数，从名字就可以看出其意义。

int mutex1 = 0;
int mutex2 = 0;

#define D_WRITE 0
#define D_FREE 1
#define D_READ 2
int read_counter=D_FREE;

char process_buff[1024];

char usr_buff1[1024];
char usr_buff2[1024];
int unlock = 1;

//count 初始值为0, 可以这么写
//__sync_fetch_and_add(&count, 1);//返回0, count现在等于1, 类似 count++
//count 初始值为0, 或者这么写
//__sync_add_and_fetch(&count, 1);//返回1, count现在等于1, 类似 ++count

//int bufIsBusy=0;
//void lock(){
//    return true;
//}
//bool trylock(){
//    return true;
//}
//void unlock(){
//    ;
//}

int update_buffer=1;
bool write(){
   if( __sync_bool_compare_and_swap(mutex1,D_FREE, D_WRITE) ){


       memcpy(usr_buff1, process_buff, sizeof(process_buff));
       update_buffer=1;
       mutex1=D_FREE;
   }else if( __sync_bool_compare_and_swap(&mutex2, D_FREE, D_WRITE) ){


       memcpy(usr_buff2, process_buff, sizeof(process_buff));
       update_buffer=2;
       mutex2=D_FREE;
   }
   else
   {

       printf("error: no empty buffer,code:0 !\n");
   }

//   if(  __sync_bool_compare_and_swap(&mutex1,D_READ, D_FREE) ){
//       read_counter=0;
//       mutex1=D_FREE;
//   }
//   if(  __sync_bool_compare_and_swap(&mutex2,D_READ, D_FREE) ){
//       read_counter=0;
//       mutex2=D_FREE;
//   }

}

bool read(){

    int state=read_counter;
    __sync_add_and_fetch(&read_counter,1);//>=2
    if( state = __sync_val_compare_and_swap(&mutex1, D_FREE, read_counter) != D_WRITE ){//>=2

        if( state==D_FREE || state==D_WRITE ){
            //one read
            __sync_sub_and_fetch(&mutex1,1);
        }
    }else if( state = __sync_val_compare_and_swap(&mutex2, D_FREE, read_counter) != D_WRITE  ){//>=2
        if( state==D_FREE || state==D_WRITE ){
            //one read
            __sync_sub_and_fetch(&mutex2,1);
        }
    }else{
        printf("error: no empty buffer,code:2 !\n");
        //
    }

    __sync_sub_and_fetch(&read_counter,1);

//    if( D_WRITE != __sync_val_compare_and_swap(&mutex2,D_FREE, read_counter) ){

//    }

}


//
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
//#include "timer.h"

int mutex = 0;
int lock = 0;
int unlock = 1;
//#define D_CAN_READ 0
//#define D_CAN_WRITE 1
static volatile int count = 0;
void *test_func(void *arg)
{
    int i = 0;
    for(i = 0; i < 2000000; i++)
    {
        while (!(__sync_bool_compare_and_swap (&mutex,lock, 1) ))
            usleep(100000);
        count++;
        __sync_bool_compare_and_swap (&mutex, unlock, 0);
    }
    return NULL;
}

int main(int argc, const char *argv[])
{
//    Timer timer;
//    timer.Start();
    pthread_t thread_ids[10];
    int i = 0;

    for(i = 0; i < sizeof(thread_ids)/sizeof(pthread_t); i++)
    {
            pthread_create(&thread_ids[i], NULL, test_func, NULL);
    }

    for(i = 0; i < sizeof(thread_ids)/sizeof(pthread_t); i++)
    {
            pthread_join(thread_ids[i], NULL);
    }

//    timer.Stop();
//    timer.Cost_time();
    printf("结果:count = %d\n",count);

    return 0;
}



#include <assert.h>
#include <string.h>

typedef unsigned char u_char;

#define CAN_WRITE 0x00
#define CAN_READ 0x01
#define READING 0x02
#define WRITING 0x03

typedef struct tag
{
    u_char tag_value;
}TAG;


class RingQueue
{
public:
    RingQueue(int nmemb,int size)
        :_nmemb(nmemb)
        , _size(size)
        ,_read_now(0)
        ,_write_now(0)
    {
        if ( nmemb <= 0 || size <=0 )
        {
            assert(0);
        }
        _queue_p = NULL;
        _queue_p = new u_char[ nmemb * (sizeof(TAG) + size)];
        memset(_queue_p,0,nmemb * (sizeof(TAG) + size));

    }

    ~RingQueue()
    {
        if (_queue_p)
            delete []_queue_p;
    }

    u_char * SOLO_Read()
    {
        u_char * g_p = 0;
        TAG * tag_p = 0;
        u_char *user_data = 0;

        g_p = queue_peek_nth(_queue_p,_read_now);
        tag_p = (TAG *)g_p;
        if (tag_p->tag_value == CAN_READ)
        {
            user_data = (u_char *)g_p + sizeof(TAG);
            tag_p->tag_value = READING;
        }
        return user_data;
    }

    void SOLO_Read_Over()
    {
        u_char * g_p = 0;
        TAG * tag_p = 0;

        g_p = queue_peek_nth(_queue_p,_read_now);
        tag_p = (TAG *)g_p;
        if (tag_p->tag_value == READING)
        {
            tag_p->tag_value = CAN_WRITE;
            _read_now = (_read_now + 1)% _nmemb;
        }
    }

    u_char * SOLO_Write()
    {
        u_char * g_p = 0;
        TAG * tag_p = 0;
        u_char *user_data = 0;

        g_p = queue_peek_nth(_queue_p,_write_now);
        tag_p = (TAG *)g_p;
        if (tag_p->tag_value == CAN_WRITE)
        {
            user_data = (u_char *)g_p + sizeof(TAG);
            tag_p->tag_value = WRITING;
        }
        return user_data;
    }

    void SOLO_Write_Over()
    {
        u_char * g_p = 0;
        TAG * tag_p = 0;

        g_p = queue_peek_nth(_queue_p,_write_now);
        tag_p = (TAG *)g_p;
        if (tag_p->tag_value == WRITING)
        {
            tag_p->tag_value = CAN_READ;
            _write_now = (_write_now + 1)% _nmemb;
        }
    }

private:
    u_char *queue_peek_nth(u_char *queue_p,int pos)
    {
        u_char *rst = 0;
        if (queue_p && pos < _nmemb)
        {
            rst = queue_p + pos * (sizeof(TAG) + _size);
        }
        return rst;
    }

    u_char * _queue_p;
    int _nmemb;
    int _size;
    volatile int _read_now;
    volatile int _write_now;
};



#endif // RINGQUEUE_H
